package manongfanshen.cas.demo01;

import com.google.common.base.Stopwatch;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;

import static org.assertj.core.api.Assertions.assertThat;

/**
 * @author ChangLiang
 * @date 2020/4/24
 */
public class AppTest {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    @Test
    @DisplayName("test Sequence: thread unsafe")
    public void test(){
        Sequence sequence = new Sequence();
        templateTest(sequence);
    }

    @Test
    @DisplayName("test SequenceV1: synchronized")
    public void test2(){
        SequenceV1 sequence = new SequenceV1();
        templateTest(sequence);
    }

    @Test
    @DisplayName("test SequenceV2: cas")
    public void test3(){
        SequenceV2 sequence = new SequenceV2();
        templateTest(sequence);
    }

    private void templateTest(Isequence sequence) {
        Stopwatch stopwatch = Stopwatch.createStarted();

        int initActiveCount = Thread.activeCount();
        logger.info("initActiveCount:{}", initActiveCount);

        IntStream.rangeClosed(1, 10).forEach(i -> new Thread("my-thread-" + i) {
            @Override
            public void run() {
                for (int j = 0; j < 100000; j++) {
                    sequence.next();
                }
            }
        }.start());

        while (Thread.activeCount() > initActiveCount) {
            Thread.yield();
        }
        logger.info("finalActiveCount:{}", Thread.activeCount());
        logger.info("sequence thread unsafe elapsed time :{} MILLISECOND", stopwatch.elapsed(TimeUnit.MILLISECONDS));
        logger.info("value:{}", sequence.getValue());
        assertThat(sequence.getValue()).isEqualTo(10000);
    }

}
